/**
 * @file
 * @brief Contains the implementation of the TPZV3DGraphMesh methods. 
 */

#include "pzv3dmesh.h"
#include "pzcmesh.h"
#include "TPZMaterial.h"
#include "pzgraphnode.h"
#include "pzgraphel.h"
#include "pzvec.h"

#include <fstream>

using namespace std;

TPZV3DGraphMesh::TPZV3DGraphMesh(TPZCompMesh *cmesh, int dimension, const std::set<int> & matids, const TPZVec<std::string> &scalarnames,
                                 const TPZVec<std::string> &vecnames) : TPZGraphMesh(cmesh,dimension,matids,scalarnames,vecnames) {
	fMesh = cmesh;
	fStyle = EV3DStyle;
	fNumCases = 0;
	fTotScal = 0;
	fInterval = 0;
	fLoadStep = 0;
	for(int i=0; i<6; i++) fNumScal[i] = 0;
}

TPZV3DGraphMesh::TPZV3DGraphMesh(TPZCompMesh *cmesh, int dimension, TPZV3DGraphMesh *graph) :
TPZGraphMesh(cmesh,dimension,graph->fMaterialIds,graph->ScalarNames(),graph->VecNames()) {
	fMesh = cmesh;
	fStyle = EV3DStyle;
	fNumCases = graph->fNumCases;
	fTotScal = graph->fTotScal;
	fInterval = graph->fInterval;
	fLoadStep = graph->fLoadStep;
	for(int i=0; i<6; i++) fNumScal[i] = graph->fNumScal[i];
}

void TPZV3DGraphMesh::DrawMesh(int numcases){
	if(!fOutFile) return;
	(fOutFile) << "File generated by the PZ environment\n";
	(fOutFile) << "2 Dimensional grid\n";
	(fOutFile) << "dim 3\n";
	(fOutFile) << "coor " << NPoints() << endl;
	DrawNodes();
	(fOutFile) << "nomax 4\n";
	MElementType eltypes[] = {ENoType, EOned, EQuadrilateral, ETriangle};
	int nel=0,type;
	for(type=1;type<4;type++)nel+= NElements(eltypes[type]);
	(fOutFile) << "elem " << nel << endl;
	for(type=1;type<4;type++)DrawConnectivity(eltypes[type]);
	fNumCases = numcases;
	fInterval = ((numcases-1)/5)+1;
	fLoadStep = 0;
}
// Draw the nodal coordinates and the connectivity

void TPZV3DGraphMesh::DrawSolution(TPZBlock<REAL> &/*Sol*/){
	cout << "TPZV3DGraphMesh::DrawSolution(TPZBlock &) not implemented\n";
}
// Draw the solution associated with Sol (not implemented)
void TPZV3DGraphMesh::DrawSolution(char * /*var*/){
	cout << "TPZV3DGraphMesh::DrawSolution(char *) not implemented\n";
}
// Draw the solution associated with the variable name
void TPZV3DGraphMesh::DrawSolution(int step, REAL /*time*/){
	if(step+1 != fNumCases && step%fInterval) return;
	int numscal = fScalarNames.NElements();
	int numvec = fVecNames.NElements();
	if(numscal > 6) {
		cout << "View3d only allows for 6 scalars numscal = " << numscal << endl;
		numscal = 6;
	}
	if(numscal+fTotScal >6) {
		cout << "View3d total number of cases cannot exceed 6 values\n";
		numscal = 6-fTotScal;
	}
	fTotScal += numscal;
	if(step < fNumCases-1 && numvec) {
		cout << "Vector values only allowed at the last step\n";
		numvec = 0;
	}
	if(numvec > 1) {
		cout << "View3d only allows for 1 vector variable = " << numvec << endl;
		numvec = 1;
	}
	if(fLoadStep < 6) fNumScal[fLoadStep] = numscal;
	fOutFile.close();
	char tempfilename[] = "temp0.dat";
	tempfilename[3] += (char) fLoadStep;
	fOutFile.open(tempfilename);
	
	TPZVec<int> scalind(numscal);
	TPZVec<int> vecind(numvec);
	scalind.Fill(-1);
	vecind.Fill(-1);
	
    std::set<int> matids = MaterialIds(); /// partial solution
    if(matids.size() == 0) {
        cout << "TPZMVGraphMesh no material found\n";
        return;
    }
    set<int>::iterator it = matids.begin();
    TPZMaterial * matp = fCompMesh->FindMaterial(*it);
	if(!matp) {
		cout << "TPZV3DGraphMesh::DrawSolution material not found" << endl;
		return;
	}
	int n;
	for(n=0; n<numscal; n++) {
		scalind[n] = matp->VariableIndex(fScalarNames[n]);
	}
	for(n=0; n<numvec; n++) {
		vecind[n] = matp->VariableIndex(fVecNames[n]);
	}
	if(numscal > 0) {
		(fOutFile) << "nosc " << numscal << endl;
		int64_t nnod = fNodeMap.NElements();
		for(int64_t i=0;i<nnod;i++) {
			TPZGraphNode *np = &fNodeMap[i];
			if(np) np->DrawSolution(scalind, fStyle);
		}
	}
	ifstream *tempread[6];
	REAL values;
	int icase;
	if(fNumCases == step+1 && fNumCases > 1) {
		for(icase=0; icase<=fLoadStep; icase++) {
			char fname[] = "temp0.dat";
			fname[3] += (char) icase;
			tempread[icase] = new ifstream(fname);
		}
		int64_t nump = NPoints();
		(fOutFile) << "nosc " << fTotScal << endl;
		char buf[256];
		for(icase=0; icase<=fLoadStep; icase++) tempread[icase]->getline(buf,255);
		for(int64_t iv=0; iv<nump; iv++) {
			for(icase=0; icase<=fLoadStep; icase++) {
				int64_t nodindex;
				(*tempread[icase]) >> nodindex;
				if(icase == 0) (fOutFile) << nodindex << ' ';
				for(int iscal=0; iscal<fNumScal[icase]; iscal++) {
					(*tempread[icase]) >> values; (fOutFile) << values << ' ';
				}
			}
			(fOutFile) << endl;
		}
		for(icase=0; icase <=fLoadStep; icase++) delete tempread[icase];
	}
	if(numvec > 0) {
		(fOutFile) << "nvec\n";
		int64_t nnod = fNodeMap.NElements();
		for(int64_t i=0;i<nnod;i++) {
			TPZGraphNode *np = &fNodeMap[i];
			if(np) np->DrawSolution(vecind, fStyle);
		}
	}
	if(step+1 == fNumCases) (fOutFile) << "fim\n";
	if(fLoadStep <5) fLoadStep++;
}

void TPZV3DGraphMesh::SequenceNodes(){
	TPZGraphMesh::SequenceNodes();
	int64_t nnod = fNodeMap.NElements();
	for(int64_t i=0;i<nnod;i++) {
		TPZGraphNode *n = &fNodeMap[i];
		if(n) n->SetPointNumber(n->FirstPoint()+1);
	}
}

